<template>
  <div>
    <el-form label-width="auto" :inline="true" :model="extraData">
      <el-form-item
        v-for="extraParameter in extraParameters"
        :key="extraParameter.paramName"
        :label="extraParameter.paramLabel"
      >
        <el-input
          v-if="extraParameter.paramType === 'string'"
          v-model="extraData[extraParameter.paramName]"
        />
        <el-switch
          v-else-if="extraParameter.paramType === 'boolean'"
          v-model="extraData[extraParameter.paramName]"
        />
      </el-form-item>
    </el-form>

    <!-- 导入映射表格 s -->
    <div class="main-container">
      <!-- 顶部操作按钮 s -->
      <div class="mb-3">
        <el-upload
          class="upload-excel"
          action="#"
          :show-file-list="false"
          accept=".xlsx"
          :auto-upload="false"
          :on-change="handleFileChange"
        >
          <el-button type="primary">选择Excel文件</el-button>
        </el-upload>
      </div>
      <div class="mb-3"></div>
      <div class="mb-3">
        <el-button type="success" @click="onDownloadTemplate">模板下载</el-button>
      </div>
      <!-- 顶部操作按钮 s -->

      <div class="h-xl w-full overflow-auto flex flex-col">
        <el-table
          class="flex-1"
          size="small"
          :data="tempTableData"
          v-loading="loading"
        >
          <!-- <el-table-column label="序号" prop="index" /> -->

          <el-table-column
            v-for="(item, idx) in headers"
            :key="item.key"
            :label="item.label"
            :prop="item.prop"
            :fixed="idx == 0 ? 'left' : undefined"
            show-overflow-tooltip
          />
        </el-table>
        <Pagination
          class="ml-auto"
          small
          :total="total"
          v-model:page="queryParams.pageNo"
          v-model:limit="queryParams.pageSize"
          @pagination="getList"
        />
        <!-- <div class="flex justify-end">
        <el-pagination class="mt-1" layout="total" :total="total" />
      </div> -->
      </div>
      <div class="border bg-light-500 p-2">
        <el-form ref="formRef" :model="formData" :show-message="true" label-width="20">
          <el-form-item
            v-for="(item, index) in targetTableColumns"
            :key="index"
            :prop="`targetTableColumns.${index}.excelProp`"
            :rules="item.rules"
            label=" "
          >
            <el-row :gutter="5" style="width: 100%">
              <el-col :span="14">
                <el-select
                  style="width: 100%"
                  v-model="item.excelProp"
                  filterable
                  clearable
                  @change="createTableData"
                  class="keep-default"
                >
                  <el-option
                    v-for="it in headers"
                    :key="it.key"
                    :label="it.label"
                    :value="it.prop"
                  />
                </el-select>
              </el-col>
              <el-col :span="10" class="">
                <div class="h-full flex items-center text-warm-gray-500">
                  <Icon icon="ep:d-arrow-right" />
                  <p class="flex-shrink-0">{{ item.label }}</p>
                  <!-- <p class="flex-shrink-0" v-if="item.label === '机构名称'">学校名称</p> -->
                </div>
              </el-col>
            </el-row>
          </el-form-item>
        </el-form>
      </div>
      <div class="h-xl w-full overflow-auto flex flex-col">
        <el-table
          size="small"
          :data="tempTargetData"
          :scroll="{ x: 'max-content' }"
          class="flex-1"
        >
          <!-- <el-table-column label="序号" prop="index" /> -->

          <el-table-column
            v-for="(item, idx) in targetTableColumns"
            :key="item.field"
            :label="item.label"
            :prop="item.field"
            :fixed="idx == 0 ? 'left' : undefined"
            show-overflow-tooltip
          />
        </el-table>
        <!-- <div class="flex justify-end">
        <el-pagination class="mt-1" layout="total" :total="total" />
      </div> -->

        <Pagination
          class="ml-auto"
          small
          :total="total"
          v-model:page="queryParams.pageNo"
          v-model:limit="queryParams.pageSize"
          @pagination="getList"
        />
      </div>
    </div>
    <!-- 导入映射表格 e -->

    <!-- tips s -->
    <div v-if="tips && tips.length" class="mt-5 bg-light-500">
      <div class="text-red-500">* 提示:</div>
      <ul class="text-gray-400">
        <li v-for="(item, idx) in tips" :key="idx">{{ item }}</li>
      </ul>
    </div>
    <!-- tips e -->

    <!-- 错误提示 s -->
    <div class="error-container mt-5">
      <div class="text-red-500">* 异常数据:</div>
      <el-table size="small" :data="tempErrorTableData.data" height="200px">
        <el-table-column label="异常信息" fixed prop="remark" show-overflow-tooltip>
          <template #default="{ row }">
            <span class="text-red-500">{{ row.message }}</span>
          </template>
        </el-table-column>
        <el-table-column
          v-for="(item, idx) in targetTableColumns"
          :key="item.field"
          :label="item.label"
          :prop="item.field"
          :fixed="idx == 0 ? 'left' : undefined"
          show-overflow-tooltip
        />
      </el-table>
      <div class="flex justify-end">
        <Pagination
          class="ml-auto"
          small
          :total="tempErrorTableData.data.length"
          v-model:page="errorTableDataPagination.pageNo"
          v-model:limit="errorTableDataPagination.pageSize"
          @pagination="getErrorTableData"
        />
      </div>
      <!-- <Pagination
      small
      :total="total"
      v-model:page="queryParams.pageNo"
      v-model:limit="queryParams.pageSize"
      @pagination="getList"
    /> -->
    </div>
    <!-- 错误提示 e -->
    <Dialog
      v-model="dialogVisible"
      :title="dialogTitle"
      :close-on-click-modal="false"
      :show-close="false"
    >
      <el-progress
        :text-inside="true"
        :stroke-width="24"
        :percentage="percentage"
        status="success"
      />
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="handleInterrupt">中止</el-button>
        </div>
      </template>
    </Dialog>
  </div>
</template>
<script lang="ts" setup>
import * as XLSX from 'xlsx'
import { ITargetTableColumbnItem, ExtraParam } from './type'
import { getIntDictOptions } from '@/utils/dict'
import { parse } from './method'

const CHUNK_SIZE = 500 // 每次切片的大小

type TProps = {
  targetTableColumns: ITargetTableColumbnItem[]
  importApi: (data?: any) => Promise<any>
  tips?: string[]
  templateName: string
  extraParameters?: ExtraParam[]
}

type TExcelColumn = {
  prop: string
  label: string
  key: string
}

const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('正在上传中...') // 弹窗的标题

const percentage = ref(0)

const tableData = ref<any>([]) // 解析后的数据
const tempTableData = ref<any>([]) // 临时数据

const targetData = ref<any>([]) // 转换后的目标数据
const tempTargetData = ref<any>([]) // 临时目标数据

const headers = ref<TExcelColumn[]>([]) // 表头

const excelData = ref<any>([])
const extraData = ref<any>({})

const total = ref(0) // 列表的总页数

const queryParams = reactive({
  pageNo: 1,
  pageSize: 30
})

const loading = ref(false)

const props = withDefaults(defineProps<TProps>(), {
  targetTableColumns: () => [],
  tips: () => []
})

// 分页
// const pagination = reactive({
//   currentPage: 1,
//   pageSize: 5,
//   pagerCount: 5,
//   total: 0
// })

// const handleSizeChange = (val: number) => {
//   console.log(`${val} items per page`)
// }

// const handleCurrentChange = (val: number) => {
//   console.log(`current page: ${val}`)
// }

const tempErrorTableData = computed(() => {
  return getPaginationData(errorTableData.value, {
    pageNo: errorTableDataPagination.value.pageNo,
    pageSize: errorTableDataPagination.value.pageSize
  })
  // return errorTableData.value.slice(
  //   (errorTableDataPagination.value.pageNo - 1) * errorTableDataPagination.value.pageSize,
  //   errorTableDataPagination.value.pageNo * errorTableDataPagination.value.pageSize
  // )
})
const getErrorTableData = ({ limit = 10, page = 1 }) => {
  errorTableDataPagination.value.pageNo = page
  errorTableDataPagination.value.pageSize = limit
}

// 清空目标数据
const clearTargetData = () => {
  targetData.value = []
}

// 清除转化数据
const clearTargetTableColumns = () => {
  formData.value.targetTableColumns.map((item) => {
    item.excelProp = undefined
  })
}

const handleFileChange = (file) => {
  console.log('file', file)
  loading.value = true
  clearTargetData()
  setTimeout(() => {
    // loading.value = false
    parseExcel(file.raw)
  }, 250)
}

// 创建Element UI表头配置函数
function createTableHeader(val): TExcelColumn[] {
  // 凑成Element UI表头配置
  const headerConfig = val
    .map((item, index) => {
      // 如果item为空，则不生成对应的表头配置
      if (item) {
        return {
          prop: item.toString(),
          label: item.toString(),
          key: index.toString()
        }
      }
    })
    .filter((header) => header) // 过滤掉空值
  console.log('headerConfig', headerConfig)

  return headerConfig
}

// 创建Element UI表格数据函数
function createTableData() {
  const result = tableData.value.map((item) => {
    const obj = {}
    props.targetTableColumns.forEach((targetItem) => {
      if (targetItem.excelProp) {
        obj[targetItem.field] = parse(cleanData(item[targetItem.excelProp]), targetItem.parseRule)
      }
    })
    return obj
  })
  console.log('createTableData', result)
  targetData.value = result
  const { data, size } = getPaginationData(excelData.value, queryParams)
  tempTableData.value = data
  total.value = size
  const { data: data2 } = getPaginationData(targetData.value, queryParams)
  tempTargetData.value = data2
  loading.value = false
}

const parseExcel = (file) => {
  console.log('parseExcel', file)
  loading.value = true

  const reader = new FileReader()
  // 读取文件内容
  reader.readAsBinaryString(file)

  // 读取文件失败后执行的方法函数
  reader.onerror = () => {
    console.log('文件读取失败！')
    loading.value = false
  }
  // 读取文件过程中执行的方法函数
  reader.onprogress = () => {
    loading.value = true
    console.log('正在读取文件！ 55555')
  }
  // 读取文件成功后执行的方法函数
  reader.onload = (e) => {
    // loading.value = false
    console.log('文件读取成功！66666', e)

    const data = e.target?.result
    const workbook = XLSX.read(data, { type: 'binary' })
    console.log('workbook', workbook)

    const firstSheetName = workbook.SheetNames[0]
    const worksheet = workbook.Sheets[firstSheetName]
    excelData.value = XLSX.utils.sheet_to_json(worksheet)

    // 读取表头
    headers.value = createTableHeader(XLSX.utils.sheet_to_json(worksheet, { header: 1 })[0])

    tableData.value = excelData.value
    // console.log('tableData.value', tableData.value)

    // 计算总行数
    total.value = excelData.value.length

    // 全等时 自动匹配
    if (props.targetTableColumns.length) {
      // console.log('自动匹配', headers.value)
      formData.value.targetTableColumns.forEach((item: any) => {
        // console.log('item.label')

        const matchedHeader = headers.value.find((header) => {
          // console.log('header.prop', header.prop, item.label, header.prop.trim() == item.label)
          return item.label === header.prop.trim()
        })

        item.excelProp = matchedHeader ? matchedHeader.prop : undefined

        // console.log('matchedHeader', item.excelProp)
        // formData.value.targetTableColumns = []
      })
    }

    // 有匹配的字段时自动创建转换数据
    if (
      (props.targetTableColumns.length &&
        formData.value.targetTableColumns.find((item) => item.excelProp)) ||
      []
    ) {
      createTableData()
      onValidate()
    }
  }
}

// 数据清洗
const cleanData = (str) => {
  if (typeof str === 'string') {
    // 去首位空格，去换行
    return str.trim().replace(/\n/g, '')
  }
  return str
}

const errorTableData = ref<any>([])
const errorTableDataPagination = ref({
  pageNo: 1,
  pageSize: 10
})

//#region 转换字段表单数据
const formRef = ref()
const formData = ref({
  targetTableColumns: props.targetTableColumns
})

const getPaginationData = (data, params) => {
  const { pageNo, pageSize } = params
  const startIndex = (pageNo - 1) * pageSize
  const endIndex = startIndex + pageSize

  const newData = data.slice(startIndex, endIndex)

  return {
    data: newData,
    size: excelData.value.length
  }
}

// 获取分页数据
const getList = () => {
  loading.value = true
  // const { data, size } = getPaginationData(queryParams)
  // console.log(' 分页数据: ', data, size)
  // tableData.value = data
  // total.value = size
  createTableData()
  loading.value = false
}

async function onValidate() {
  const isValid = await formRef.value.validate().catch(() => false)
  console.log('valida', isValid)
  return isValid
}

const continueProcessing = ref(true) // 控制是否继续处理的标志位

// 分片请求
async function sliceAndRequest(data, importApi) {
  return new Promise((resolve) => {
    const { items, update } = data
    const slicedItems = []

    for (let i = 0; i < items.length; i += CHUNK_SIZE) {
      const chunk = items.slice(i, i + CHUNK_SIZE)
      slicedItems.push(chunk)
    }

    let success = true

    const processSlice = async (index) => {
      if (!continueProcessing.value) {
        dialogVisible.value = false
        resolve(false)
        return
      }

      try {
        const res = await importApi({ items: slicedItems[index], update })
        console.log('import res99', res && res.length > 0)
        console.log('percentage 百分比啊啊啊', index + 1, slicedItems.length)

        percentage.value = parseFloat(((index / slicedItems.length) * 100).toFixed(2))

        if (res && res.length > 0) {
          errorTableData.value.push(...res)
          success = false
        }

        if (index + 1 === slicedItems.length) {
          resolve(success)
          return
        }

        processSlice(index + 1)
      } catch (e) {
        console.log('ooooooo')
        success = false
        resolve(false)
      }
    }

    processSlice(0)
  })
}

// 中断处理按钮点击事件
function handleInterrupt() {
  dialogVisible.value = false
  continueProcessing.value = false // 设置标志位为 false，中断处理
}

async function onSubmit() {
  const isValid = await onValidate()
  if (!isValid) return

  const items = unref(targetData)
  console.log('post items', items)
  if (!items || !items.length) {
    ElMessage.warning('请设置需要导入的数据!')
    return false
  }

  try {
    dialogVisible.value = true

    console.log('extraData.value', extraData.value)
    const isSuccess = await sliceAndRequest(
      {
        items,
        ...extraData.value
      },
      props.importApi
    )

    if (!isSuccess) {
      dialogVisible.value = false
      return false
    } else {
      dialogVisible.value = false
      return true
    }
  } catch (e) {
    return false
  }

  // return true
}
//#endregion

// #region 下载模板
function onDownloadTemplate() {
  const rows = props.targetTableColumns.map((item) => {
    return {
      [item.label]: null
    }
  })
  const worksheet = XLSX.utils.json_to_sheet(rows)
  console.log('worksheet', props.targetTableColumns, worksheet, rows)
  const workbook = XLSX.utils.book_new()
  console.log('workbook', workbook)
  XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
  XLSX.writeFile(workbook, `${props.templateName}模板.xlsx`)
}
//#endregion
defineExpose({
  onValidate,
  onSubmit
})

const initGradeMap = () => {
  props.targetTableColumns.map((item) => {
    const map = {}
    if (item.parseRule) {
      // 没设置指定的转换规则并且设置了数据字典，就查回来组
      if (!item.parseRule.parseMap && item.parseRule.dictType) {
        const dictOptions =
          getIntDictOptions(item.parseRule.dictType) || item.parseRule.defaultValue
        dictOptions.forEach((item) => {
          map[item.label] = item.value
          map[item.value] = item.value
        })
        item.parseRule.parseMap = map
      }
    }
  })
}

onMounted(() => {
  initGradeMap()
})

onUnmounted(() => {
  console.log('灭了', headers.value)

  // createTableData()
  clearTargetTableColumns()
  // formData.value.targetTableColumns = formData.value.targetTableColumns.map((item) => ({
  //   item: undefined
  // }))
  // console.log('onUnmounted', formData.value.targetTableColumns)
})
</script>

<style lang="scss" scoped>
.main-container {
  // background: pink;
  display: grid;
  min-height: 200px;
  grid-template-columns: 3fr min(220px) 3fr;
  // grid-template-rows: 1fr;
  grid-gap: 0 10px;
}
</style>
